﻿#pragma once

#include <string>
#include <queue>
#include <source_location>
#include <fast_io/fast_io.h>
#include <fast_io/fast_io_device.h>

#include "Utils.h"

enum class LogGrade : uint8_t {
	trace = 0ui8,
	debug,
	info,
	warning,
	error,
	fatal,
	chat_log
};

class Logger final {
public:
	__forceinline static constexpr std::u8string_view GetGradeName(LogGrade grade) noexcept {
		switch (grade) {
		case LogGrade::trace:
			return u8"[TRACE] ";
		case LogGrade::debug:
			return u8"[DEBUG] ";
		case LogGrade::info:
			return u8"[INFO] ";
		case LogGrade::warning:
			return u8"[WARN] ";
		case LogGrade::error:
			return u8"[ERROR] ";
		case LogGrade::fatal:
			return u8"[FATAL] ";
		case LogGrade::chat_log:
			return u8"[CHAT] ";
		}
		std::unreachable();
		return std::u8string_view{};
	}
	static void Enable() noexcept;
	static void Disable() noexcept;
	static void Refresh() noexcept;
	static void Log(LogGrade grade, std::u8string_view sv) noexcept;
	static void LogF(LogGrade grade, const char8_t* args, ...);  // not safe

	template <typename... Args>
	static constexpr void LogC(LogGrade grade, Args&&... args) {  // Log to file only
#ifdef _DEBUG
		const auto time = fast_io::mnp::left(local(fast_io::posix_clock_gettime(fast_io::posix_clock_id::realtime)), 34);
		const auto GradeName = GetGradeName(grade);
		println(log_file, time, GradeName, args...);
		can_refresh = true;
		println(fast_io::u8dbg(), u8"[Helium DBG] ", time, GradeName, args...);
#else
		println(log_file, fast_io::mnp::left(local(fast_io::posix_clock_gettime(fast_io::posix_clock_id::realtime)), 34), GetGradeName(grade), args...);
		can_refresh = true;
#endif  // _DEBUG
	}

#ifdef _DEBUG
	static void ShowTraceStack() noexcept;

#ifdef HELIUM_USE_SIGNUM
	static void AbortSignal(int signum) noexcept;
#else
	static void AbortSignal() noexcept;
#endif  // 0
#endif

private:
	static fast_io::u8obuf_file_mutex log_file;  // Remember to delete
	static bool can_refresh; 
};

